<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>报表管理</title>
  <link rel="stylesheet" href="../assets/styles.css" />
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body class="body-bg">
  <header class="header">
    <div class="title datav-title">河北省高速公路联网收费省级密钥资源池管理系统</div>
  </header>
  <div class="layout">
    <aside class="sidebar">
      <!-- <div class="logo">密钥资源池</div> -->
      <div class="logo">报表管理</div>
      <nav class="menu">
        <a href="../index.html">首页</a>
        <a href="app.html">应用管理</a>
        <a href="crypto.html">加密设备状态</a>
        <a href="security.html">安全设备状态</a>
        <a href="network.html">部省密钥网络状态</a>
        <a href="jobs.html">定时任务</a>
      </nav>
      <div class="tree">
         <div class="tree-node expanded">
           <div class="tree-header">报表管理<span class="chevron"></span></div>
           <div class="tree-children">
             <a class="tree-link active" href="javascript:void(0)" data-tab="app">服务调用统计</a>
             <a class="tree-link" href="javascript:void(0)" data-tab="crypto">加密设备运行监测</a>
             <a class="tree-link" href="javascript:void(0)" data-tab="security">安全设备运行监测</a>
             <a class="tree-link" href="javascript:void(0)" data-tab="network">部省密钥网络运行报表</a>
           </div>
         </div>
       </div>
    </aside>
    <div class="content">
      <main class="container">
    <!-- 子菜单改为侧栏，移除顶部标签 -->

    <!-- 应用管理报表 -->
    <section class="card" data-content="app">
      <h3>报表筛选区</h3>
      <div class="filters">
        <select id="appRange" class="select"><option>今日</option><option>近7天</option></select>
        <input class="input" type="date" />
        <input class="input" type="date" />
        <input id="appApi" class="input" placeholder="接口名称" />
        <select class="select"><option>全部</option><option>成功</option><option>失败</option></select>
        <select id="appAlgo" class="select"><option value="">算法类型</option><option>国密</option><option>3DES</option></select>
        <button class="button" id="appQuery">查询</button>
        <button class="button secondary" id="appReset">重置</button>
        <button class="button success" onclick="exportTable('tblApp','应用管理报表')">导出 Excel</button>
      </div>
      <h3 style="margin-top:12px;">报表展示区</h3>
      <table class="table" id="tblApp">
        <thead><tr><th>接口名称</th><th>算法类型</th><th>总调用</th><th>成功</th><th>失败</th><th>成功率</th><th>平均耗时(ms)</th><th>调用峰值时段</th></tr></thead>
        <tbody>
          <tr><td>CPU卡一发更新密钥</td><td class="col-algo"></td><td>1200</td><td>1189</td><td>11</td><td>99.08%</td><td>38</td><td>10:00-11:00</td></tr>
          <tr><td>CPC卡更新密钥</td><td class="col-algo"></td><td>980</td><td>940</td><td>40</td><td>95.92%</td><td>45</td><td>14:00-15:00</td></tr>
        </tbody>
      </table>
      <div id="appPager" style="margin-top:10px; display:flex; gap:8px; align-items:center;">
        <button class="button secondary" id="appPrev">上一页</button>
        <span id="appPageInfo">第 1 / 1 页</span>
        <button class="button secondary" id="appNext">下一页</button>
        <span style="margin-left:12px;">每页</span>
        <select class="select" id="appPerPage">
          <option value="5" selected>5</option>
          <option value="10">10</option>
          <option value="20">20</option>
        </select>
        <span>条</span>
      </div>
      <div class="chart-box" style="margin-top:12px; height:280px;"><canvas id="chartAppCalls7d"></canvas></div>
    </section>

    <!-- 加密设备状态监控报表 -->
    <section class="card" data-content="crypto" style="display:none;">
      <h3>报表筛选区</h3>
      <div class="filters">
        <input class="input" placeholder="设备ID" />
        <input class="input" placeholder="设备型号" />
        <select id="cryptoRange" class="select"><option>今日</option><option>近7天</option></select>
        <select class="select"><option>全部</option><option>成功</option><option>失败</option></select>
        <button class="button">查询</button>
        <button class="button secondary">重置</button>
        <button class="button success" onclick="exportTable('tblCrypto','加密设备报表')">导出 Excel</button>
      </div>
      <h3 style="margin-top:12px;">报表展示区</h3>
      <table class="table" id="tblCrypto">
        <thead><tr><th>设备ID</th><th>型号</th><th>设备名称</th><th>总调用</th><th>成功</th><th>失败</th><th>安全运行总时长(h)</th><th>最高调用时段</th></tr></thead>
        <tbody>
          <tr><td>ENC-001</td><td>SM4-A</td><td>国密加密机</td><td>3000</td><td>2985</td><td>15</td><td>3421</td><td>10:00-11:00</td></tr>
          <tr class="tr-yellow"><td>ENC-003</td><td>SM4-C</td><td>国密加密机</td><td>500</td><td>440</td><td>60</td><td>1120</td><td>20:00-21:00</td></tr>
        </tbody>
      </table>
      <div id="cryptoPager" style="margin-top:10px; display:flex; gap:8px; align-items:center;">
        <button class="button secondary" id="cryptoPrev">上一页</button>
        <span id="cryptoPageInfo">第 1 / 1 页</span>
        <button class="button secondary" id="cryptoNext">下一页</button>
        <span style="margin-left:12px;">每页</span>
        <select class="select" id="cryptoPerPage">
          <option value="5" selected>5</option>
          <option value="10">10</option>
          <option value="20">20</option>
        </select>
        <span>条</span>
      </div>
      <div class="chart-box" style="margin-top:12px; height:280px;"><canvas id="chartCryptoCalls7d"></canvas></div>
    </section>

    <!-- 安全设备状态监控报表 -->
    <section class="card" data-content="security" style="display:none;">
      <h3>报表筛选区</h3>
      <div class="filters">
        <select class="select"><option>签名验签服务器</option><option>SSL 网关</option></select>
        <input class="input" placeholder="设备ID" />
        <input class="input" placeholder="IP 地址" />
        <select class="select"><option>今日</option><option>近7天</option></select>
        <button class="button">查询</button>
        <button class="button secondary">重置</button>
        <button class="button success" onclick="exportTable('tblSecurity','安全设备报表')">导出 Excel</button>
      </div>
      <h3 style="margin-top:12px;">报表展示区</h3>
      <table class="table" id="tblSecurity">
        <thead><tr><th>设备ID</th><th>类型</th><th>设备名称</th><th>IP</th><th>总调用</th><th>失败次数</th><th>最近心跳</th><th>成功率</th></tr></thead>
        <tbody>
          <tr><td>SEC-101</td><td>验签</td><td>验签设备</td><td>10.0.1.101</td><td>1290</td><td>9</td><td>09:12</td><td>99.3%</td></tr>
          <tr><td>SSL-202</td><td>网关</td><td>网关设备</td><td>10.0.2.202</td><td>1120</td><td>11</td><td>09:12</td><td>99.0%</td></tr>
        </tbody>
      </table>
      <div id="securityPager" style="margin-top:10px; display:flex; gap:8px; align-items:center;">
        <button class="button secondary" id="securityPrev">上一页</button>
        <span id="securityPageInfo">第 1 / 1 页</span>
        <button class="button secondary" id="securityNext">下一页</button>
        <span style="margin-left:12px;">每页</span>
        <select class="select" id="securityPerPage">
          <option value="5" selected>5</option>
          <option value="10">10</option>
          <option value="20">20</option>
        </select>
        <span>条</span>
      </div>
      <div class="chart-box" style="margin-top:12px; height:280px;"><canvas id="chartSecuritySuccess7d"></canvas></div>
    </section>

    <!-- 部省两级网络状态管理报表 -->
    <section class="card" data-content="network" style="display:none;">
      <h3>报表筛选区</h3>
      <div class="filters">
        <select class="select"><option>今日</option></select>
        <select class="select"><option>全部</option><option>成功</option><option>失败</option></select>
        <button class="button">查询</button>
        <button class="button secondary">重置</button>
        <button class="button success" onclick="exportTable('tblNetwork','网络状态报表')">导出 Excel</button>
      </div>
      <h3 style="margin-top:12px;">报表展示区</h3>
      <table class="table" id="tblNetwork">
        <thead><tr><th>总检测</th><th>成功</th><th>失败</th><th>平均延迟(ms)</th><th>最高延迟时段</th><th>可用率</th></tr></thead>
        <tbody>
          <tr><td>1400</td><td>1396</td><td>4</td><td>10</td><td>10:00-11:00</td><td>99.71%</td></tr>
        </tbody>
      </table>
      <div class="chart-box" style="margin-top:12px; height:280px;"><canvas id="chartNetworkSuccess7d"></canvas></div>
    </section>
      </main>
    </div>
  </div>

  <script>
    // 树状菜单展开/折叠
    const treeHeader = document.querySelector('.tree-header');
    if (treeHeader) treeHeader.addEventListener('click', () => treeHeader.parentElement.classList.toggle('expanded'));

    // 左侧树状子菜单切换报表
    function showTab(tab) {
      document.querySelectorAll('.tree-link').forEach(l=>l.classList.toggle('active', l.getAttribute('data-tab')===tab));
      document.querySelectorAll('[data-content]').forEach(sec => {
        sec.style.display = sec.getAttribute('data-content') === tab ? '' : 'none';
      });
    }
    const qp = new URLSearchParams(location.search);
    const initTab = qp.get('tab') || 'app';
    showTab(initTab);
    document.querySelectorAll('.tree-link').forEach(item => {
      item.addEventListener('click', () => {
        showTab(item.getAttribute('data-tab'));
        history.replaceState(null,'',`?tab=${item.getAttribute('data-tab')}`);
      });
    });

    // 导出为 CSV（Excel 可打开）
    function exportTable(tableId, filename) {
      const table = document.getElementById(tableId);
      let csv = '';
      table.querySelectorAll('tr').forEach(row => {
        const cells = Array.from(row.children).map(td => '"' + td.textContent.replace(/"/g,'""') + '"');
        csv += cells.join(',') + '\n';
      });
      const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
      const a = document.createElement('a');
      a.href = URL.createObjectURL(blob);
      a.download = filename + '.csv';
      a.click();
      URL.revokeObjectURL(a.href);
    }

    // 图表：加密设备近30天趋势
    new Chart(document.getElementById('chartCryptoTrend'), {
      type: 'line',
      data: { labels: Array.from({length:30},(_,i)=>`D-${30-i}`), datasets: [{ label:'ENC-001 调用量', data: Array.from({length:30},()=> Math.floor(300+Math.random()*100)), borderColor:'#3b82f6', tension:.3 }] },
    });

    // 图表：安全设备成功率折线（近7天）
    (function initSecuritySuccess7d(){
      const el = document.getElementById('chartSecuritySuccess7d');
      if (!el) return;
      const labels = Array.from({length:7}, (_,i)=>`D-${7-i}`);
      const data = Array.from({length:7}, ()=> +(99 + Math.random()).toFixed(2));
      new Chart(el, {
        type: 'line',
        data: { labels, datasets: [{ label:'成功率(%)', data, borderColor:'#10b981', backgroundColor:'rgba(16,185,129,0.18)', tension:.3, fill:true, pointRadius:3 }] },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          plugins: { legend: { labels: { color:'#e5e7eb' } } },
          scales: {
            x: { ticks: { color:'#cbd5e1' }, grid: { color:'rgba(148,163,184,0.12)' } },
            y: { ticks: { color:'#cbd5e1' }, grid: { color:'rgba(148,163,184,0.12)' }, suggestedMin: 98, suggestedMax: 100 }
          }
        }
      });
    })();

    // 图表：网络成功率折线（近7天）
    (function initNetworkSuccess7d(){
      const el = document.getElementById('chartNetworkSuccess7d');
      if (!el) return;
      const labels = Array.from({length:7}, (_,i)=>`D-${7-i}`);
      const data = Array.from({length:7}, ()=> +(99 + Math.random()).toFixed(2));
      new Chart(el, {
        type: 'line',
        data: { labels, datasets: [{ label:'成功率(%)', data, borderColor:'#10b981', backgroundColor:'rgba(16,185,129,0.18)', tension:.3, fill:true, pointRadius:3 }] },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          plugins: { legend: { labels: { color:'#e5e7eb' } } },
          scales: {
            x: { ticks: { color:'#cbd5e1' }, grid: { color:'rgba(148,163,184,0.12)' } },
            y: { ticks: { color:'#cbd5e1' }, grid: { color:'rgba(148,163,184,0.12)' }, suggestedMin: 98, suggestedMax: 100 }
          }
        }
      });
    })();
    // 安全设备报表：表格分页（默认每页5条）
    (function securityTablePagination(){
      const table = document.getElementById('tblSecurity');
      if (!table) return;
      const tbody = table.querySelector('tbody');
      const rows = Array.from(tbody.querySelectorAll('tr'));
      const btnPrev = document.getElementById('securityPrev');
      const btnNext = document.getElementById('securityNext');
      const perSelect = document.getElementById('securityPerPage');
      const pageInfo = document.getElementById('securityPageInfo');
      let page = 1;
      let per = parseInt(perSelect.value || '5', 10);

      function render(){
        const total = rows.length;
        const totalPages = Math.max(1, Math.ceil(total / per));
        page = Math.min(page, totalPages);
        const start = (page - 1) * per;
        const end = start + per;
        rows.forEach((tr, idx) => {
          tr.style.display = (idx >= start && idx < end) ? '' : 'none';
        });
        pageInfo.textContent = `第 ${page} / ${totalPages} 页`;
        btnPrev.disabled = page <= 1;
        btnNext.disabled = page >= totalPages;
      }

      btnPrev.addEventListener('click', () => { if (page > 1) { page--; render(); } });
      btnNext.addEventListener('click', () => { page++; render(); });
      perSelect.addEventListener('change', () => { per = parseInt(perSelect.value, 10) || 5; page = 1; render(); });

      render();
    })();
  </script>
  <script>
    // 应用管理报表：为“算法类型”列随机赋值（国密/3DES），并绑定查询/重置
    (function appAlgoInitAndFilter(){
      const tbody = document.querySelector('#tblApp tbody');
      if (!tbody) return;
      const algos = ['国密','3DES'];
      // 随机填充算法类型
      Array.from(tbody.querySelectorAll('tr')).forEach(tr => {
        const cell = tr.querySelector('.col-algo');
        if (cell) cell.textContent = algos[Math.floor(Math.random()*algos.length)];
      });

      // 简单筛选（接口名称与算法类型）
      const btnQuery = document.getElementById('appQuery');
      const btnReset = document.getElementById('appReset');
      const selAlgo = document.getElementById('appAlgo');
      const iptApi = document.getElementById('appApi');
      function applyFilter(){
        const wantAlgo = selAlgo && selAlgo.value ? selAlgo.value : '';
        const wantApi = (iptApi && iptApi.value ? iptApi.value : '').trim().toLowerCase();
        Array.from(tbody.querySelectorAll('tr')).forEach(tr => {
          const apiName = tr.children[0].textContent.toLowerCase();
          const algoText = (tr.querySelector('.col-algo')?.textContent || '');
          const okAlgo = !wantAlgo || algoText === wantAlgo;
          const okApi = !wantApi || apiName.includes(wantApi);
          tr.style.display = (okAlgo && okApi) ? '' : 'none';
        });
      }
      btnQuery && btnQuery.addEventListener('click', applyFilter);
      btnReset && btnReset.addEventListener('click', () => {
        if (selAlgo) selAlgo.value = '';
        if (iptApi) iptApi.value = '';
        Array.from(tbody.querySelectorAll('tr')).forEach(tr => tr.style.display = '');
      });
    })();
  </script>
  <script>
    // 加密设备报表：总调用数近7天折线图
    (function initCryptoCalls7d(){
      const el = document.getElementById('chartCryptoCalls7d');
      if (!el) return;
      const labels = Array.from({length: 7}, (_, i) => `D-${7 - i}`);
      const data = Array.from({length: 7}, () => 500 + Math.floor(Math.random() * 300));
      new Chart(el, {
        type: 'line',
        data: { labels, datasets: [{ label: '总调用数', data, borderColor: '#10b981', backgroundColor: 'rgba(16,185,129,0.20)', tension: .3, fill: true, pointRadius: 3 }] },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          plugins: { legend: { labels: { color: '#e5e7eb' } } },
          scales: {
            x: { ticks: { color: '#cbd5e1' }, grid: { color: 'rgba(148,163,184,0.12)' } },
            y: { ticks: { color: '#cbd5e1' }, grid: { color: 'rgba(148,163,184,0.12)' } }
          }
        }
      });
    })();
  </script>
  <script>
    // 加密设备报表：根据“今日/近7天”动态设置最高调用时段区间显示
    (function bindCryptoPeakInterval(){
      const rangeSel = document.getElementById('cryptoRange');
      const tbody = document.querySelector('#tblCrypto tbody');
      if (!rangeSel || !tbody) return;
      const pad2 = n => String(n).padStart(2, '0');
      const formatDate = dt => `${dt.getFullYear()}-${pad2(dt.getMonth()+1)}-${pad2(dt.getDate())}`;
      function hourlyInterval(){
        const h = Math.floor(Math.random()*24);
        const s = pad2(h);
        const e = pad2((h+1)%24);
        return `${s}:00-${e}:00`;
      }
      function updatePeak(){
        const val = rangeSel.value;
        Array.from(tbody.querySelectorAll('tr')).forEach(tr => {
          const lastTd = tr.lastElementChild;
          if (!lastTd) return;
          if (val === '今日') {
            lastTd.textContent = hourlyInterval();
          } else if (val === '近7天') {
            const offsetDays = Math.floor(Math.random()*7);
            const day = new Date(Date.now() - offsetDays * 24 * 60 * 60 * 1000);
            lastTd.textContent = `${formatDate(day)} 00:00-24:00`;
          } else {
            lastTd.textContent = '00:00-24:00';
          }
        });
      }
      rangeSel.addEventListener('change', updatePeak);
      updatePeak();
    })();
  </script>
  <script>
    // 加密设备报表：表格分页（默认每页5条）
    (function cryptoTablePagination(){
      const table = document.getElementById('tblCrypto');
      if (!table) return;
      const tbody = table.querySelector('tbody');
      const rows = Array.from(tbody.querySelectorAll('tr'));
      const btnPrev = document.getElementById('cryptoPrev');
      const btnNext = document.getElementById('cryptoNext');
      const perSelect = document.getElementById('cryptoPerPage');
      const pageInfo = document.getElementById('cryptoPageInfo');
      let page = 1;
      let per = parseInt(perSelect.value || '5', 10);

      function render(){
        const total = rows.length;
        const totalPages = Math.max(1, Math.ceil(total / per));
        page = Math.min(page, totalPages);
        const start = (page - 1) * per;
        const end = start + per;
        rows.forEach((tr, idx) => {
          tr.style.display = (idx >= start && idx < end) ? '' : 'none';
        });
        pageInfo.textContent = `第 ${page} / ${totalPages} 页`;
        btnPrev.disabled = page <= 1;
        btnNext.disabled = page >= totalPages;
      }

      btnPrev.addEventListener('click', () => { if (page > 1) { page--; render(); } });
      btnNext.addEventListener('click', () => { page++; render(); });
      perSelect.addEventListener('change', () => { per = parseInt(perSelect.value, 10) || 5; page = 1; render(); });

      render();
    })();
  </script>
  <script>
    // 应用管理报表：表格分页（默认每页5条）
    (function appTablePagination(){
      const table = document.getElementById('tblApp');
      if (!table) return;
      const tbody = table.querySelector('tbody');
      const rows = Array.from(tbody.querySelectorAll('tr'));
      const btnPrev = document.getElementById('appPrev');
      const btnNext = document.getElementById('appNext');
      const perSelect = document.getElementById('appPerPage');
      const pageInfo = document.getElementById('appPageInfo');
      let page = 1;
      let per = parseInt(perSelect.value || '5', 10);

      function render(){
        const total = rows.length;
        const totalPages = Math.max(1, Math.ceil(total / per));
        page = Math.min(page, totalPages);
        const start = (page - 1) * per;
        const end = start + per;
        rows.forEach((tr, idx) => {
          tr.style.display = (idx >= start && idx < end) ? '' : 'none';
        });
        pageInfo.textContent = `第 ${page} / ${totalPages} 页`;
        btnPrev.disabled = page <= 1;
        btnNext.disabled = page >= totalPages;
      }

      btnPrev.addEventListener('click', () => { if (page > 1) { page--; render(); } });
      btnNext.addEventListener('click', () => { page++; render(); });
      perSelect.addEventListener('change', () => { per = parseInt(perSelect.value, 10) || 5; page = 1; render(); });

      // 初始化渲染（默认每页5条）
      render();
    })();
  </script>
  <script>
    // 应用管理报表：总调用数近7天折线图
    (function initAppCalls7d(){
      const el = document.getElementById('chartAppCalls7d');
      if (!el) return;
      const labels = Array.from({length: 7}, (_, i) => `D-${7 - i}`);
      const data = Array.from({length: 7}, () => 800 + Math.floor(Math.random() * 400));
      new Chart(el, {
        type: 'line',
        data: { labels, datasets: [{ label: '总调用数', data, borderColor: '#3b82f6', backgroundColor: 'rgba(59,130,246,0.20)', tension: .3, fill: true, pointRadius: 3 }] },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          plugins: { legend: { labels: { color: '#e5e7eb' } } },
          scales: {
            x: { ticks: { color: '#cbd5e1' }, grid: { color: 'rgba(148,163,184,0.12)' } },
            y: { ticks: { color: '#cbd5e1' }, grid: { color: 'rgba(148,163,184,0.12)' } }
          }
        }
      });
    })();
  </script>
  <script>
    // 应用管理报表：根据“今日/近7天”动态设置调用峰值时段的区间显示
    (function bindAppPeakInterval(){
      const rangeSel = document.getElementById('appRange');
      const tbody = document.querySelector('#tblApp tbody');
      if (!rangeSel || !tbody) return;
      const pad2 = n => String(n).padStart(2, '0');
      const formatDate = dt => `${dt.getFullYear()}-${pad2(dt.getMonth()+1)}-${pad2(dt.getDate())}`;
      function hourlyInterval(){
        const h = Math.floor(Math.random()*24);
        const s = pad2(h);
        const e = pad2((h+1)%24);
        return `${s}:00-${e}:00`;
      }
      function updatePeak(){
        const val = rangeSel.value;
        Array.from(tbody.querySelectorAll('tr')).forEach(tr => {
          const lastTd = tr.lastElementChild;
          if (!lastTd) return;
          if (val === '今日') {
            lastTd.textContent = hourlyInterval();
          } else if (val === '近7天') {
            const offsetDays = Math.floor(Math.random()*7); // 近7天内的某一天
            const day = new Date(Date.now() - offsetDays * 24 * 60 * 60 * 1000);
            lastTd.textContent = `${formatDate(day)} 00:00-24:00`;
          } else {
            lastTd.textContent = '00:00-24:00';
          }
        });
      }
      rangeSel.addEventListener('change', updatePeak);
      // 初次渲染根据当前选择设置
      updatePeak();
    })();
  </script>
</body>
</html>